﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web;
using System.Text;
using System.Threading;
namespace ARC.Common.Log
{
    public class Logger : IDisposable
    {
        /// <summary>
        /// 日志文件日志条数限制
        /// </summary>
        public int LogFileMaxLength { get; set; }
        /// <summary>
        /// 是否启用日志文件大小限制
        /// </summary>
        public bool LogFileSizeLimitEnabled { get; set; }
        /// <summary>
        /// 日志目录
        /// </summary>
        public string LogFolder { get; private set; }

        public string LogFileNamePrefix { get; set; }

        public int LogThreadSleep { get; set; }

        private Queue<Log> _logQueue = null;
        private StreamWriter _logWriter = null;
        private Thread _logThread = null;
        private int _currentLogLength = 0;

        public string _fileName = null;

        private static Random _r = new Random();


        private static int QUEUE_SIZE = 1000000;


        public Logger(string logFolder, string prefix = "arclog_")
        {
            LogFolder = logFolder;
            _logQueue = new Queue<Log>(QUEUE_SIZE);

            LogFileSizeLimitEnabled = true;
            LogFileNamePrefix = prefix;
            LogFileMaxLength = 5000;
            LogThreadSleep = 2;
            _fileName = GetNewLogFileName();

            if (!Directory.Exists(LogFolder))
            {
                Directory.CreateDirectory(LogFolder);
            }

            _logThread = new Thread(LogCore);
            _logThread.Start();
        }

        private string GetNewLogFileName()
        {
            string fileName = string.Format("{0}\\{1}{2:yyyyMMddHHmm}-{3}.log", LogFolder.Trim('\\'), LogFileNamePrefix, DateTime.Now, _r.Next(100, 999));
            if (File.Exists(fileName))
            {
                return GetNewLogFileName();
            }
            return fileName;
        }


        public void Log(Log Log)
        {
            lock (_logQueue)
            {
                _logQueue.Enqueue(Log);
            }
        }

        public void Log(string log)
        {
            Log logObj = new Log { LogContent = log };

            lock (_logQueue)
            {
                _logQueue.Enqueue(logObj);
            }
        }

        private void LogCore()
        {
            while (true)
            {
                Log log = null;
                if (_logQueue.Count > 0)
                {
                    if (_logWriter == null)
                    {
                        _logWriter = new StreamWriter(_fileName, true);
                    }

                    log = _logQueue.Dequeue();
                    if (log != null)
                    {
                        _logWriter.WriteLine("{0:yyyy-MM-dd HH:mm:ss}\t{1}", log.LogTime, log.LogContent);
                        _logWriter.Flush();
                        _currentLogLength++;

                        if (LogFileSizeLimitEnabled && _currentLogLength >= LogFileMaxLength)
                        {
                            _logWriter.Close();
                            _fileName = GetNewLogFileName();
                            _logWriter = new StreamWriter(_fileName);
                            _currentLogLength = 0;
                        }
                    }
                }
                else
                {
                    if (_logWriter != null)
                    {
                        _logWriter.Close();
                        _logWriter = null;
                    }
                    Thread.Sleep(LogThreadSleep * 1000);
                }
            }
        }

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (_logWriter != null)
            {
                _logWriter.Dispose();
            }
        }
    }

    public class Log
    {
        public DateTime LogTime { get; set; }
        public string LogContent { get; set; }

        public Log()
        {
            LogTime = DateTime.Now;
        }
    }
}